#include "stdafx.h"

#include "../Driver.h"
#include "rmath.h"

namespace Driver
{

namespace 
{

size_t GetGridIndex(const ArrayGrid& ag, size_t i, size_t j)
{
    return j + i * ag.m;
}

Real MagicHelper(Real x, Real y, Real t, Real v)
{
    static const Real pi = boost::math::constants::pi<Real>();

    Real numerator = expr(-(sqr(x - v) + sqr(y)) / static_cast<Real>(2.0) / t);
    Real denominator = powr(static_cast<Real>(2.0) * pi * t, static_cast<Real>(1.5));

    Real rv =  numerator / denominator;

    return rv;
}

Real MagicFunction(const FunctionArguments& args, Real x, Real y)
{
    Real rv = MagicHelper(x, y, args.t0, args.v0) + MagicHelper(x, y, args.t1, args.v1);
    return rv;
}

void FillArrayGridData(const ArrayGrid& ag, const FunctionArguments& args)
{
    const Real hx = (args.xe - args.xb) / args.n;
    const Real hy = (args.ye - args.yb) / args.m;

    Real x = args.xb;
    for (size_t i = 0; i < args.n; ++i)
    {
        
        Real y = args.yb;
        for (size_t j = 0; j < args.m; ++j)
        {
            ag.data[GetGridIndex(ag, i, j)] = MagicFunction(args, x, y);
            y += hy;
        }
        x += hx;
    }
}

} // namespace

Real GetArrayGridValue(const ArrayGrid& ag, size_t i, size_t j)
{
    return ag.data[GetGridIndex(ag, i, j)];
}

void SetArrayGridValue(const ArrayGrid& ag, size_t i, size_t j, Real value)
{
    ag.data[GetGridIndex(ag, i, j)] = value;
}

ArrayGrid GetValuesArrayGrid(const FunctionArguments& args)
{
    assert(args.n > 0 && args.m > 0);
    ArrayGrid ag = { NULL, args.n, args.m };

    size_t ag_size = args.n * args.m;
    if (ag_size == 0)
    {
        return ag;
    }

    ag.data = new Real[ag_size];
    FillArrayGridData(ag, args);
    
    return ag;
}

void FreeArrayGrid(ArrayGrid& ag)
{
    delete[] ag.data;
    ag.m = 0;
    ag.n = 0;
}

} // namespace Driver
